package com.demo.base.redis.helper;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @author 曳戈泰尔
 * @version 1.0
 * @description Redis分布式锁
 * @date 2023/3/10 3:57 PM
 */
@Component
@Slf4j
public class RedisLockHelper {

    /** 注入stringRedisTemplate */
    private final StringRedisTemplate stringRedisTemplate;

    @Autowired
    public RedisLockHelper(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * Redis加锁的操作
     *
     * @param key
     * @param value
     * @return
     */
    public Boolean tryLock(String key, String value) {

        // 加锁
        if (Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(key, value))) {
            return true;
        }

        // 其他人获取不到锁执行如下代码
        // 获取锁的值
        String currentValue = stringRedisTemplate.opsForValue().get(key);

        // 锁的值小于当前时则锁已过期
        if (StringUtils.isNotEmpty(currentValue)
                && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            // 获取上一个锁的时间 如果高并发的情况可能会出现已经被修改的问题  所以多一次判断保证线程的安全
            String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, value);
            // 比较锁的getSet获取到的最近锁值和最开始获取到的锁值，如果不相等则证明锁已经被其他线程获取了
            return StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue);
        }

        return false;
    }

    /**
     * Redis解锁的操作
     *
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {

        String currentValue = stringRedisTemplate.opsForValue().get(key);

        try {
            if (StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)) {
                stringRedisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception ex) {
            log.error("Redis分布式锁解锁失败，原因：{}", ex.getMessage());
        }
    }
}
